package jmine.tec.web.wicket.cronExpression;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import jmine.tec.utils.date.MonthEnum;
import jmine.tec.utils.date.WeekDaysEnum;

import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.ListMultipleChoice;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;

/**
 * Strategy to create cron expressions of FIXED_SCHEDULE. This strategy allows fixed schedule only (without interval), but allows the user
 * to choose the days, months and week days that will trigger the cron expression. These last three options are optional, and if not
 * selected, will be considered as '*', '?', except the week days, that will be 'MON-FRI'.
 * 
 * @author Fabio Sakiyama
 * @created 24/11/2011
 */
public class FixedScheduleStrategy extends AbstractCronExpressionTypeStrategy {

    /**
     * C'tor
     * 
     * @param id id
     */
    public FixedScheduleStrategy(String id) {
        super(id);
    }

    private String selectMinute;

    private String selectHour;

    private List<String> daysList = new ArrayList<String>();

    private List<MonthEnum> monthsList = new ArrayList<MonthEnum>();

    private List<WeekDaysEnum> weekDaysList = new ArrayList<WeekDaysEnum>();

    /**
     * {@inheritDoc}
     */
    @Override
    public String doBuildCronExpression() {
        StringBuffer cronExpression = new StringBuffer();
        cronExpression.append("0 "); // seconds
        cronExpression.append(this.selectMinute);
        cronExpression.append(" ");
        cronExpression.append(this.selectHour);
        cronExpression.append(" ");
        cronExpression.append(this.formatDaysMonthsWeekDays(this.daysList, this.monthsList, this.weekDaysList));
        cronExpression.append("*"); // year
        return cronExpression.toString();
    }

    /**
     * {@inheritDoc}
     */
    public void populateScreenFields(String cronExpression) {
        this.daysList.clear();
        this.monthsList.clear();
        this.weekDaysList.clear();

        String[] splittedCronExpression = cronExpression.split(" ");
        this.selectMinute = splittedCronExpression[MINUTE_POSITION];
        this.selectHour = splittedCronExpression[HOUR_POSITION];

        if (splittedCronExpression[DAYS_POSITION].equals("?") || splittedCronExpression[DAYS_POSITION].equals("*")) {
            this.daysList.addAll(this.maxDaysMonth());
        } else {
            String[] selectedDays = splittedCronExpression[DAYS_POSITION].split(",");
            for (String day : selectedDays) {
                this.daysList.add(day);
            }
        }

        if (splittedCronExpression[MONTHS_POSITION].equals("*")) {
            this.monthsList.addAll(Arrays.asList(MonthEnum.values()));
        } else {
            String[] selectedMonths = splittedCronExpression[MONTHS_POSITION].split(",");
            for (String month : selectedMonths) {
                this.monthsList.add(MonthEnum.valueOf(this.getMonthNameByNumber(month)));
            }
        }

        if (splittedCronExpression[WEEK_DAYS_POSITION].equals("?") || splittedCronExpression[WEEK_DAYS_POSITION].equals("*")) {
            this.weekDaysList.addAll(Arrays.asList(WeekDaysEnum.values()));
        } else {
            String[] selectedWeekDays = splittedCronExpression[WEEK_DAYS_POSITION].split(",");
            for (String weekDay : selectedWeekDays) {
                this.weekDaysList.add(this.getWeekDayNameByWeekDayInitial(weekDay));
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public Panel buildScreenFields(IModel<String> iModel, OptionalComponentsEnum... excludeFields) {
        this.setiModel(iModel);

        WebMarkupContainer containerDays = new WebMarkupContainer("containerDays");
        WebMarkupContainer containerMonths = new WebMarkupContainer("containerMonths");
        WebMarkupContainer containerWeekDays = new WebMarkupContainer("containerWeekDays");

        this.setOutputMarkupId(true);
        this.setOutputMarkupPlaceholderTag(true);

        // XXX fabio.sakiyama internacionalizar..
        Label labelDay = new Label("labelDay", "Dias: ");
        Label labelMonth = new Label("labelMonth", "Meses: ");
        Label labelWeekDay = new Label("labelWeekDay", "Dias da Semana: ");

        final DropDownChoice<String> selectMinuteDropDown = this.createMinutesDropDownChoice("selectMinute");
        final DropDownChoice<String> selectHourDropDown = this.createHourDropDownChoice("selectHour");

        ListMultipleChoice<String> daysListMultipleChoice = this.createDaysListMultipleChoice("multipleListDays");
        ListMultipleChoice<MonthEnum> monthsListMultipleChoice = this.createMonthsListMultipleChoice("multipleListMonths");
        ListMultipleChoice<WeekDaysEnum> weekDaysListMultipleChoice = this.createWeekDaysListMultipleChoice("multipleListWeekDays");

        selectMinuteDropDown.setRequired(true);
        selectHourDropDown.setRequired(true);

        containerDays.add(labelDay);
        containerDays.add(daysListMultipleChoice);
        containerMonths.add(labelMonth);
        containerMonths.add(monthsListMultipleChoice);
        containerWeekDays.add(labelWeekDay);
        containerWeekDays.add(weekDaysListMultipleChoice);

        this.addOrReplace(containerDays);
        this.addOrReplace(containerMonths);
        this.addOrReplace(containerWeekDays);
        this.addOrReplace(selectMinuteDropDown);
        this.addOrReplace(selectHourDropDown);

        if (excludeFields != null) {
            for (OptionalComponentsEnum comp : excludeFields) {
                if (comp.isDays()) {
                    containerDays.setVisible(false);
                } else if (comp.isMonths()) {
                    containerMonths.setVisible(false);
                } else if (comp.isWeekDays()) {
                    containerWeekDays.setVisible(false);
                }
            }
        }
        return this;
    }

    /**
     * {@inheritDoc}
     */
    public boolean nullCheckAllFields() {
        if (this.daysList == null || this.monthsList == null || this.weekDaysList == null || this.selectMinute == null
                || this.selectHour == null) {
            return false;
        }
        return true;
    }

    /**
     * @return the selectMinute
     */
    public String getSelectMinute() {
        return this.selectMinute;
    }

    /**
     * @param selectMinute the selectMinute to set
     */
    public void setSelectMinute(String selectMinute) {
        this.selectMinute = selectMinute;
        this.buildCronExpression();
    }

    /**
     * @return the selectHour
     */
    public String getSelectHour() {
        return this.selectHour;
    }

    /**
     * @param selectHour the selectHour to set
     */
    public void setSelectHour(String selectHour) {
        this.selectHour = selectHour;
        this.buildCronExpression();
    }

    /**
     * @return the daysList
     */
    public List<String> getDaysList() {
        return this.daysList;
    }

    /**
     * @param daysList the daysList to set
     */
    public void setDaysList(List<String> daysList) {
        this.daysList = daysList;
        this.buildCronExpression();
    }

    /**
     * @return the monthsList
     */
    public List<MonthEnum> getMonthsList() {
        return this.monthsList;
    }

    /**
     * @param monthsList the monthsList to set
     */
    public void setMonthsList(List<MonthEnum> monthsList) {
        this.monthsList = monthsList;
        this.buildCronExpression();
    }

    /**
     * @return the weekDaysList
     */
    public List<WeekDaysEnum> getWeekDaysList() {
        return this.weekDaysList;
    }

    /**
     * @param weekDaysList the weekDaysList to set
     */
    public void setWeekDaysList(List<WeekDaysEnum> weekDaysList) {
        this.weekDaysList = weekDaysList;
        this.buildCronExpression();
    }
}
